<!DOCTYPE html>
<html CN>







<head>
	
	
	<link rel="stylesheet" href="/css/allinone.min.css"> 

	
	<!-- Global Site Tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id=UA-42863699-1"></script>
	<script>
		window.dataLayer = window.dataLayer || [];
		function gtag(){dataLayer.push(arguments);}
		gtag('js', new Date());
		gtag('config', 'UA-42863699-1');
	</script>
	

	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />

	<title>Go 语言 JSON 简介 | Cizixs Write Here</title>

	<meta name="HandheldFriendly" content="True" />
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
	<meta name="generator" content="hexo">
	<meta name="author" content="Cizixs Wu">
	<meta name="description" content="">

	
	<meta name="keywords" content="">
	

	
	<link rel="shortcut icon" href="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg">
	

	
	<meta name="theme-color" content="#3c484e">
	<meta name="msapplication-TileColor" content="#3c484e">
	

	

	

	<meta property="og:site_name" content="Cizixs Write Here">
	<meta property="og:type" content="article">
	<meta property="og:title" content="Go 语言 JSON 简介 | Cizixs Write Here">
	<meta property="og:description" content="">
	<meta property="og:url" content="http://cizixs.com/2016/12/19/golang-json-guide/">

	
	<meta property="article:published_time" content="2016-12-19T00:12:00+08:00"/> 
	<meta property="article:author" content="Cizixs Wu">
	<meta property="article:published_first" content="Cizixs Write Here, /2016/12/19/golang-json-guide/" />
	

	
	
	<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
	

	
	<script src="https://cdn.staticfile.org/highlight.js/9.10.0/highlight.min.js"></script>
	

	
	
<link rel="stylesheet" href="/css/prism-base16-ateliersulphurpool.light.css" type="text/css"></head>
<body class="post-template">
    <div class="site-wrapper">
        




<header class="site-header outer" style="z-index: 999">
    <div class="inner">
        
<nav class="site-nav"> 
    <div class="site-nav-left">
        <ul class="nav">
            <li>
                
                <a href="/" title="Home">Home</a>
                
            </li>
            
            
            <li>
                <a href="/about" title="About">About</a>
            </li>
            
            <li>
                <a href="/archives" title="Archives">Archives</a>
            </li>
            
            
        </ul> 
    </div>
    <div class="site-nav-right">
        
<div class="social-links" >
    
    <a class="social-link" title="weibo" href="https://weibo.com/1921727853" target="_blank" rel="noopener">
        <svg viewBox="0 0 1141 1024" xmlns="http://www.w3.org/2000/svg"><path d="M916.48 518.144q27.648 21.504 38.912 51.712t9.216 62.976-14.336 65.536-31.744 59.392q-34.816 48.128-78.848 81.92t-91.136 56.32-94.72 35.328-89.6 18.944-75.264 7.68-51.712 1.536-49.152-2.56-68.096-10.24-78.336-21.504-79.872-36.352-74.24-55.296-59.904-78.848q-16.384-29.696-22.016-63.488t-5.632-86.016q0-22.528 7.68-51.2t27.136-63.488 53.248-75.776 86.016-90.112q51.2-48.128 105.984-85.504t117.248-57.856q28.672-10.24 63.488-11.264t57.344 11.264q10.24 11.264 19.456 23.04t12.288 29.184q3.072 14.336 0.512 27.648t-5.632 26.624-5.12 25.6 2.048 22.528q17.408 2.048 33.792-1.536t31.744-9.216 31.232-11.776 33.28-9.216q27.648-5.12 54.784-4.608t49.152 7.68 36.352 22.016 17.408 38.4q2.048 14.336-2.048 26.624t-8.704 23.04-7.168 22.016 1.536 23.552q3.072 7.168 14.848 13.312t27.136 12.288 32.256 13.312 29.184 16.384zM658.432 836.608q26.624-16.384 53.76-45.056t44.032-64 18.944-75.776-20.48-81.408q-19.456-33.792-47.616-57.344t-62.976-37.376-74.24-19.968-80.384-6.144q-78.848 0-139.776 16.384t-105.472 43.008-72.192 60.416-38.912 68.608q-11.264 33.792-6.656 67.072t20.992 62.976 42.496 53.248 57.856 37.888q58.368 25.6 119.296 32.256t116.224 0.512 100.864-21.504 74.24-33.792zM524.288 513.024q20.48 8.192 38.912 18.432t32.768 27.648q10.24 12.288 17.92 30.72t10.752 39.424 1.536 42.496-9.728 38.912q-8.192 18.432-19.968 37.376t-28.672 35.328-40.448 29.184-57.344 18.944q-61.44 11.264-117.76-11.264t-88.064-74.752q-12.288-39.936-13.312-70.656t16.384-66.56q13.312-27.648 40.448-51.712t62.464-38.912 75.264-17.408 78.848 12.8zM361.472 764.928q37.888 3.072 57.856-18.432t21.504-48.128-15.36-47.616-52.736-16.896q-27.648 3.072-43.008 23.552t-17.408 43.52 9.728 42.496 39.424 21.504zM780.288 6.144q74.752 0 139.776 19.968t113.664 57.856 76.288 92.16 27.648 122.88q0 33.792-16.384 50.688t-35.328 17.408-35.328-14.336-16.384-45.568q0-40.96-22.528-77.824t-59.392-64.512-84.48-43.52-96.768-15.872q-31.744 0-47.104-15.36t-14.336-34.304 18.944-34.304 51.712-15.36zM780.288 169.984q95.232 0 144.384 48.64t49.152 146.944q0 30.72-10.24 43.52t-22.528 11.264-22.528-14.848-10.24-35.84q0-60.416-34.816-96.256t-93.184-35.84q-19.456 0-28.672-10.752t-9.216-23.04 9.728-23.04 28.16-10.752z" /></svg>
    </a>
    

    
    <a class="social-link" title="github" href="https://github.com/cizixs" target="_blank" rel="noopener">
        <svg viewBox="0 0 1049 1024" xmlns="http://www.w3.org/2000/svg"><path d="M524.979332 0C234.676191 0 0 234.676191 0 524.979332c0 232.068678 150.366597 428.501342 358.967656 498.035028 26.075132 5.215026 35.636014-11.299224 35.636014-25.205961 0-12.168395-0.869171-53.888607-0.869171-97.347161-146.020741 31.290159-176.441729-62.580318-176.441729-62.580318-23.467619-60.841976-58.234462-76.487055-58.234463-76.487055-47.804409-32.15933 3.476684-32.15933 3.476685-32.15933 53.019436 3.476684 80.83291 53.888607 80.83291 53.888607 46.935238 79.963739 122.553122 57.365291 152.97411 43.458554 4.345855-33.897672 18.252593-57.365291 33.028501-70.402857-116.468925-12.168395-239.022047-57.365291-239.022047-259.012982 0-57.365291 20.860106-104.300529 53.888607-140.805715-5.215026-13.037566-23.467619-66.926173 5.215027-139.067372 0 0 44.327725-13.906737 144.282399 53.888607 41.720212-11.299224 86.917108-17.383422 131.244833-17.383422s89.524621 6.084198 131.244833 17.383422C756.178839 203.386032 800.506564 217.29277 800.506564 217.29277c28.682646 72.1412 10.430053 126.029806 5.215026 139.067372 33.897672 36.505185 53.888607 83.440424 53.888607 140.805715 0 201.64769-122.553122 245.975415-239.891218 259.012982 19.121764 16.514251 35.636014 47.804409 35.636015 97.347161 0 70.402857-0.869171 126.898978-0.869172 144.282399 0 13.906737 9.560882 30.420988 35.636015 25.205961 208.601059-69.533686 358.967656-265.96635 358.967655-498.035028C1049.958663 234.676191 814.413301 0 524.979332 0z" /></svg>
    </a>
    

    
    <a class="social-link" title="stackoverflow" href="https://stackoverflow.com/users/1925083/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 21h-10v-2h10v2zm6-11.665l-1.621-9.335-1.993.346 1.62 9.335 1.994-.346zm-5.964 6.937l-9.746-.975-.186 2.016 9.755.879.177-1.92zm.538-2.587l-9.276-2.608-.526 1.954 9.306 2.5.496-1.846zm1.204-2.413l-8.297-4.864-1.029 1.743 8.298 4.865 1.028-1.744zm1.866-1.467l-5.339-7.829-1.672 1.14 5.339 7.829 1.672-1.14zm-2.644 4.195v8h-12v-8h-2v10h16v-10h-2z"/></svg>
    </a>
    

    

    
    <a class="social-link" title="twitter" href="https://twitter.com/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>

    </a>
    

    
    <a class="social-link" title="instagram" href="https://www.instagram.com/cizixs/" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
    </a>
    
    
    
</div>
    </div>
</nav>
    </div>
</header>


<main id="site-main" class="site-main outer" role="main">
    <div class="inner">
        <header class="post-full-header">
            <section class="post-full-meta">
                <time  class="post-full-meta-date" datetime="2016-12-18T16:00:00.000Z" itemprop="datePublished">
                    2016-12-19
                </time>
                
                <span class="date-divider">/</span>
                
                <a href="/categories/blog/">blog</a>&nbsp;&nbsp;
                
                
            </section>
            <h1 class="post-full-title">Go 语言 JSON 简介</h1>
        </header>
        <article class="post-full no-image">
            
            <section class="post-full-content">
                <div id="lightgallery" class="markdown-body">
                    <h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p><a href="http://json.org" target="_blank" rel="noopener">JSON</a>（JavaScript Object Notation） 是一种轻量级的数据交换格式，因为易读性、机器容易处理而变得流行。</p>
<p>JSON 语言定义的内容非常简洁，主要分为三种类型：对象（object）、数组（array）和基本类型（value）。基本类型（value）包括：</p>
<ul>
<li>string 字符串，双引号括起来的 unciode 字符序列</li>
<li>number 数字，可以是整数，也可以是浮点数，但是不支持八进制和十六进制表示的数字</li>
<li>true，false 真值和假值，一般对应语言中的 bool 类型</li>
<li>null 空值，对应于语言中的空指针等</li>
</ul>
<p>数组（array）就是方括号括<code>[]</code>起来的任意值的序列，中间以逗号 <code>,</code> 隔开。对象（object）是一系列无序的键值组合，<strong>键必须是字符串</strong>，键值对之间以逗号 <code>,</code> 隔开，键和值以冒号 <code>:</code> 隔开。数组和对象中的值都可以是嵌套的。</p>
<p><a href="http://json.org" target="_blank" rel="noopener">JSON 官网</a> 有非常易懂的图示，进一步了解可以移步。</p>
<p>JSON 不依赖于任何具体的语言，但是和大多数 C 家族的编程语言数据结构特别相似，所以 JSON 成了多语言之间数据交换的流行格式。Go 语言也不例外，标准库 <code>encoding/json</code> 就是专门处理 JSON 转换的。</p>
<p>这篇文章就专门介绍 Go 语言中怎么和 JSON 打交道，常用的模式以及需要注意的事项。</p>
<h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p>Golang 的 <code>encoding/json</code> 库已经提供了很好的封装，可以让我们很方便地进行 JSON 数据的转换。</p>
<p>Go 语言中数据结构和 JSON 类型的对应关系如下表：</p>
<table>
<thead>
<tr>
<th>golang 类型</th>
<th>JSON 类型</th>
<th>注意事项</th>
</tr>
</thead>
<tbody>
<tr>
<td>bool</td>
<td>JSON booleans</td>
<td></td>
</tr>
<tr>
<td>浮点数、整数</td>
<td>JSON numbers</td>
<td></td>
</tr>
<tr>
<td>字符串</td>
<td>JSON strings</td>
<td>字符串会转换成 UTF-8 进行输出，无法转换的会打印对应的 unicode 值。而且为了防止浏览器把 json 输出当做 html， “&lt;”、”&gt;” 以及 “&amp;” 会被转义为 “\u003c”、”\u003e” 和 “\u0026”。</td>
</tr>
<tr>
<td>array，slice</td>
<td>JSON arrays</td>
<td>[]byte 会被转换为 base64 字符串，nil slice 会被转换为 JSON null</td>
</tr>
<tr>
<td>struct</td>
<td>JSON objects</td>
<td>只有导出的字段（以大写字母开头）才会在输出中</td>
</tr>
</tbody>
</table>
<p><strong>NOTE</strong>：Go 语言中一些特殊的类型，比如 Channel、complex、function 是不能被解析成 JSON 的。</p>
<h3 id="Encode-和-Decode"><a href="#Encode-和-Decode" class="headerlink" title="Encode 和 Decode"></a>Encode 和 Decode</h3><p>要把 golang 的数据结构转换成 JSON 字符串（encode），可以使用 <code>Marshal</code>函数：</p>
<pre><code>func Marshal(v interface{}) ([]byte, error)
</code></pre><p>比如我们有结构体 <code>User</code></p>
<pre><code>type User struct {
    Name string
    IsAdmin bool
    Followers uint
}
</code></pre><p>以及一个实例：</p>
<pre><code>user := User{
        Name:      &quot;cizixs&quot;,
        IsAdmin:   true,
        Followers: 36,
    }
data, err := json.Marshal(user)
</code></pre><p>那么 data 就是 <code>[]byte</code> 类型的数组，里面包含了解析为 JSON 之后的数据：</p>
<pre><code>data == []byte(`{&quot;Name&quot;:&quot;cizixs&quot;,&quot;IsAdmin&quot;:true,&quot;Followers&quot;:36}`)
</code></pre><p>相对应的，要把 JSON 数据转换成 Go 类型的值（Decode）， 可以使用 <code>json.Unmarshal</code>。它的定义是这样的：</p>
<pre><code>func Unmarshal(data []byte, v interface{}) error
</code></pre><p>data 中存放的是 JSON 值，v 会存放解析后的数据，所以必须是指针，可以保证函数中做的修改能保存下来。</p>
<p>下面看个例子：</p>
<pre><code>data = []byte(`{&quot;Name&quot;:&quot;gopher&quot;,&quot;IsAdmin&quot;:false,&quot;Followers&quot;:8900}`)
var newUser = new(User)
err = json.Unmarshal(data, &amp;newUser)
if err != nil {
    fmt.Errorf(&quot;Can not decode data: %v\n&quot;, err)
}
fmt.Printf(&quot;%v\n&quot;, newUser)
</code></pre><p>那么 <code>Unmarshal</code> 是怎么找到结构体中对应的值呢？比如给定一个 JSON key <code>Filed</code>，它是这样查找的：</p>
<ul>
<li>首先查找 tag 名字（关于 JSON tag 的解释参看下一节）为 <code>Field</code> 的字段</li>
<li>然后查找名字为 <code>Field</code> 的字段</li>
<li>最后再找名字为 <code>FiElD</code> 等大小写不敏感的匹配字段。</li>
<li>如果都没有找到，就直接忽略这个 key，也不会报错。这对于要从众多数据中只选择部分来使用非常方便。</li>
</ul>
<h3 id="更多控制：Tag"><a href="#更多控制：Tag" class="headerlink" title="更多控制：Tag"></a>更多控制：Tag</h3><p>在定义 struct 字段的时候，可以在字段后面添加 tag，来控制 encode/decode 的过程：是否要 decode/encode 某个字段，JSON 中的字段名称是什么。</p>
<p>可以选择的控制字段有三种：</p>
<ul>
<li><code>-</code>：不要解析这个字段</li>
<li><code>omitempty</code>：当字段为空（默认值）时，不要解析这个字段。比如 false、0、nil、长度为 0 的 array，map，slice，string</li>
<li><code>FieldName</code>：当解析 json 的时候，使用这个名字</li>
</ul>
<p>举例来说吧：</p>
<pre><code>// 解析的时候忽略该字段。默认情况下会解析这个字段，因为它是大写字母开头的
Field int   `json:&quot;-&quot;`

// 解析（encode/decode） 的时候，使用 `other_name`，而不是 `Field`
Field int   `json:&quot;other_name&quot;`

// 解析的时候使用 `other_name`，如果struct 中这个值为空，就忽略它
Field int   `json:&quot;other_name,omitempty&quot;`
</code></pre><h3 id="解析动态内容-interface"><a href="#解析动态内容-interface" class="headerlink" title="解析动态内容: interface{}"></a>解析动态内容: interface{}</h3><p>上面的解析过程有一个假设——你要事先知道要解析的 JSON 内容格式，然后定义好对应的数据结构。如果你不知道要解析的内容呢？ Go 提供了 <code>interface{}</code> 的格式，这个接口没有限定任何的方法，因此所有的类型都是满足这个接口的。在解析 JSON 的时候，任意动态的内容都可以解析成 <code>interface{}</code>。</p>
<p>比如还是上面的数据，我们可以这样做：</p>
<pre><code>data := []byte(`{&quot;Name&quot;:&quot;cizixs&quot;,&quot;IsAdmin&quot;:true,&quot;Followers&quot;:36}`)

var f interface{}
json.Unmarshal(data, &amp;f)
</code></pre><p>但是要使用 <code>f</code>，还是很麻烦的，我们要使用 <a href="https://golang.org/ref/spec#Type_assertions" target="_blank" rel="noopener">type assertion</a>：</p>
<pre><code>name := f.(map[string]interface{})[&quot;Name&quot;].(string)
</code></pre><p>对于比较复杂的结构，这样的访问很麻烦，也很容易出错。</p>
<p>如果已经知道 JSON 数据是对象，而不是基本类型（bool，number，string，array）等，因为 JSON 对象键都是字符串，所以可以把上面的例子修改为：</p>
<pre><code>var f map[string]interface{}

// 省去了上面 f 的 type assertion 步骤
name := f[&quot;Name&quot;].(string)
</code></pre><p>需要注意的是，尽管 <code>Followers</code> 字段没有小数点，我们希望它是整数值，解析的时候它还是会被解析成 <code>float64</code>，如果直接把它当做 <code>int</code> 访问，会出现错误：</p>
<pre><code>followers := f[&quot;Followers&quot;].(int)

// panic: interface conversion: interface is float64, not int
</code></pre><p>而必须自己做类型转换：</p>
<pre><code>followers := int(f[&quot;Followers&quot;].(float64))
</code></pre><h3 id="延迟解析：json-RawMessage"><a href="#延迟解析：json-RawMessage" class="headerlink" title="延迟解析：json.RawMessage"></a>延迟解析：json.RawMessage</h3><p>在解析的时候，还可以把某部分先保留为 JSON 数据不要解析，等到后面得到更多信息的时候再去解析。继续拿 <code>User</code> 举例，比如我们要添加认证的信息，认证可以是用户名和密码，也可以是 token 认证。</p>
<pre><code>type BasicAuth struct {
    Email string
    Password string
}

type TokenAuth struct {
    Token string
}

type User struct {
    Name string
    IsAdmin bool
    Followers uint
    Auth json.RawMessage
}
</code></pre><p>我们在定义 <code>User</code> 结构体的时候，把认证字段的类型定义为 <code>json.RawMessage</code>，这样解析 JSON 数据的时候，对应的字段会先不急着转换成 Go 数据结构。然后我们可以自己去再次调用 <code>Unmarshal</code> 去读取里面的值：</p>
<pre><code>err := json.Unmarshal(data, &amp;basicAuth)
if basicAuth.Email != &quot;&quot; {
    // 这是用户名/密码认证方式，在这里继续做一些处理
} else {
    json.Unmarshal(data, &amp;tokenAuth)
    if tokenAuth.Token != &quot;&quot; {
        // 这是 token 认证方法
    }
}

</code></pre><h3 id="自定义解析方法"><a href="#自定义解析方法" class="headerlink" title="自定义解析方法"></a>自定义解析方法</h3><p>如果希望自己控制怎么解析成 JSON，或者把 JSON 解析成自定义的类型，只需要实现对应的接口（interface）。<code>encoding/json</code> 提供了两个接口：<code>Marshaler</code> 和 <code>Unmarshaler</code>：</p>
<pre><code>// Marshaler 接口定义了怎么把某个类型 encode 成 JSON 数据
type Marshaler interface {
        MarshalJSON() ([]byte, error)
}

// Unmarshaler 接口定义了怎么把 JSON 数据 decode 成特定的类型数据。如果后续还要使用 JSON 数据，必须把数据拷贝一份
type Unmarshaler interface {
        UnmarshalJSON([]byte) error
}
</code></pre><p>标准库 <a href="https://golang.org/src/time/time.go#L928" target="_blank" rel="noopener"><code>time.Time</code></a> 就实现了这两个接口。另外一个简单的例子（这个例子来自于参考资料中 Go and JSON 文章）：</p>
<pre><code>type Month struct {
    MonthNumber int
    YearNumber int
}

func (m Month) MarshalJSON() ([]byte, error){
    return []byte(fmt.Sprintf(&quot;%d/%d&quot;, m.MonthNumber, m.YearNumber)), nil
}

func (m *Month) UnmarshalJSON(value []byte) error {
    parts := strings.Split(string(value), &quot;/&quot;)
    m.MonthNumber = strconv.ParseInt(parts[0], 10, 32)
    m.YearNumber = strconv.ParseInt(parts[1], 10, 32)

    return nil
}
</code></pre><h3 id="和-stream-中-JSON-打交道"><a href="#和-stream-中-JSON-打交道" class="headerlink" title="和 stream 中 JSON 打交道"></a>和 stream 中 JSON 打交道</h3><p>上面所有的 JSON 数据来源都是预先定义的 <code>[]byte</code> 缓存，在很多时候，如果能读取/写入其他地方的数据就好了。<code>encoding/json</code> 库中有两个专门处理这个事情的结构：<code>Decoder</code> 和 <code>Encoder</code>：</p>
<pre><code>// Decoder 从 r io.Reader 中读取数据，`Decode(v interface{})` 方法把数据转换成对应的数据结构
func NewDecoder(r io.Reader) *Decoder

// Encoder 的 `Encode(v interface{})` 把数据结构转换成对应的 JSON 数据，然后写入到 w io.Writer 中
func NewEncoder(w io.Writer) *Encoder
</code></pre><p>下面的例子就是从标准输入流中读取数据，解析成数据结构，删除所有键不是 <code>Name</code> 的字段，然后再 encode 成 JSON 数据，打印到标准输出。</p>
<pre><code>package main

import (
    &quot;encoding/json&quot;
    &quot;log&quot;
    &quot;os&quot;
)

func main() {
    dec := json.NewDecoder(os.Stdin)
    enc := json.NewEncoder(os.Stdout)
    for {
        var v map[string]interface{}
        if err := dec.Decode(&amp;v); err != nil {
            log.Println(err)
            return
        }
        for k := range v {
            if k != &quot;Name&quot; {
                delete(v, k)
            }
        }
        if err := enc.Encode(&amp;v); err != nil {
            log.Println(err)
        }
    }
}
</code></pre><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><a href="https://blog.golang.org/json-and-go" target="_blank" rel="noopener">Go Blog: JSON and Go</a></li>
<li><a href="http://eagain.net/articles/go-dynamic-json/" target="_blank" rel="noopener">Dynamic JSON in Go</a></li>
<li><a href="https://eager.io/blog/go-and-json/" target="_blank" rel="noopener">Go and JSON</a></li>
</ul>

                </div>
            </section>
        </article>
    </div>
    
<nav class="pagination">
    
    
    <a class="prev-post" title="让 CPU 告诉你硬盘和网络到底有多慢" href="/2017/01/03/how-slow-is-disk-and-network/">
        ← 让 CPU 告诉你硬盘和网络到底有多慢
    </a>
    
    <span class="prev-next-post">•</span>
    
    <a class="next-post" title="跟着 Github 学习 Restful HTTP API 设计" href="/2016/12/12/restful-api-design-guide/">
        跟着 Github 学习 Restful HTTP API 设计 →
    </a>
    
    
</nav>

    <div class="inner">
    <!-- Begin Mailchimp Signup Form -->
    <link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">
    <style type="text/css">
    	#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
    	/* Add your own Mailchimp form style overrides in your site stylesheet or in this style block.
    	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
    </style>
    <div id="mc_embed_signup">
    <form action="https://cizixs.us7.list-manage.com/subscribe/post?u=2d561b8dea52d73a2e05e6dcb&amp;id=5c710f135b" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
        <div id="mc_embed_signup_scroll">
    	<h2>订阅本博客，第一时间收到文章更新</h2>
    <div class="indicates-required"><span class="asterisk">*</span> indicates required</div>
    <div class="mc-field-group">
    	<label for="mce-EMAIL">邮件地址  <span class="asterisk">*</span>
    </label>
    	<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
    </div>
    	<div id="mce-responses" class="clear">
    		<div class="response" id="mce-error-response" style="display:none"></div>
    		<div class="response" id="mce-success-response" style="display:none"></div>
    	</div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
        <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_2d561b8dea52d73a2e05e6dcb_5c710f135b" tabindex="-1" value=""></div>
        <div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
        </div>
    </form>
    </div>
    <script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
    <!--End mc_embed_signup-->
    </div>

    <div class="inner">
        <div id="disqus_thread"></div>
    </div>

    
</main>

<div class="t-g-control">
    <div class="gotop">
        <svg class="icon" width="32px" height="32px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M793.024 710.272a32 32 0 1 0 45.952-44.544l-310.304-320a32 32 0 0 0-46.4 0.48l-297.696 320a32 32 0 0 0 46.848 43.584l274.752-295.328 286.848 295.808z" fill="#8a8a8a" /></svg>
    </div>
    <div class="toc-control">
        <svg class="icon toc-icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M779.776 480h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M779.776 672h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M256 288a32 32 0 1 0 0 64 32 32 0 0 0 0-64M392.576 352h387.2a32 32 0 0 0 0-64h-387.2a32 32 0 0 0 0 64M256 480a32 32 0 1 0 0 64 32 32 0 0 0 0-64M256 672a32 32 0 1 0 0 64 32 32 0 0 0 0-64" fill="#8a8a8a" /></svg>
        <svg class="icon toc-close" style="display: none;" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M512 960c-247.039484 0-448-200.960516-448-448S264.960516 64 512 64 960 264.960516 960 512 759.039484 960 512 960zM512 128.287273c-211.584464 0-383.712727 172.128262-383.712727 383.712727 0 211.551781 172.128262 383.712727 383.712727 383.712727 211.551781 0 383.712727-172.159226 383.712727-383.712727C895.712727 300.415536 723.551781 128.287273 512 128.287273z" fill="#8a8a8a" /><path d="M557.05545 513.376159l138.367639-136.864185c12.576374-12.416396 12.672705-32.671738 0.25631-45.248112s-32.704421-12.672705-45.248112-0.25631l-138.560301 137.024163-136.447897-136.864185c-12.512727-12.512727-32.735385-12.576374-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.248112l136.255235 136.671523-137.376804 135.904314c-12.576374 12.447359-12.672705 32.671738-0.25631 45.248112 6.271845 6.335493 14.496116 9.504099 22.751351 9.504099 8.12794 0 16.25588-3.103239 22.496761-9.247789l137.567746-136.064292 138.687596 139.136568c6.240882 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.05545 513.376159z" fill="#8a8a8a" /></svg>
    </div>
    <div class="gobottom">
        <svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M231.424 346.208a32 32 0 0 0-46.848 43.584l297.696 320a32 32 0 0 0 46.4 0.48l310.304-320a32 32 0 1 0-45.952-44.544l-286.848 295.808-274.752-295.36z" fill="#8a8a8a" /></svg>
    </div>
</div>
<div class="toc-main" style="right: -100%">
    <div class="post-toc">
        <span>TOC</span>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#简介"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#使用"><span class="toc-text">使用</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Encode-和-Decode"><span class="toc-text">Encode 和 Decode</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#更多控制：Tag"><span class="toc-text">更多控制：Tag</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#解析动态内容-interface"><span class="toc-text">解析动态内容: interface{}</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#延迟解析：json-RawMessage"><span class="toc-text">延迟解析：json.RawMessage</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#自定义解析方法"><span class="toc-text">自定义解析方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#和-stream-中-JSON-打交道"><span class="toc-text">和 stream 中 JSON 打交道</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#参考资料"><span class="toc-text">参考资料</span></a></li></ol>
    </div>
</div>



        

<aside class="read-next outer">
    <div class="inner">
        <div class="read-next-feed">
            
            

<article class="read-next-card"  style="background-image: url(https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxcn9ft3j318w0txdo6.jpg)"  >
  <header class="read-next-card-header">
    <small class="read-next-card-header-sitetitle">&mdash; Cizixs Write Here &mdash;</small>
    <h3 class="read-next-card-header-title">Recent Posts</h3>
  </header>
  <div class="read-next-divider">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
      <path d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5"/>
    </svg>
  </div>
  <div class="read-next-card-content">
    <ul>
      
      
      
      <li>
        <a href="/2018/08/26/what-is-istio/">什么是 istio</a>
      </li>
      
      
      
      <li>
        <a href="/2018/08/25/knative-serverless-platform/">serverless 平台 knative 简介</a>
      </li>
      
      
      
      <li>
        <a href="/2018/06/25/kubernetes-resource-management/">kubernetes 资源管理概述</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/24/use-prometheus-and-grafana-to-monitor-linux-machine/">使用 promethues 和 grafana 监控自己的 linux 机器</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/13/linux-udp-packet-drop-debug/">linux 系统 UDP 丢包问题分析思路</a>
      </li>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </ul>
  </div>
  <footer class="read-next-card-footer">
    <a href="/archives">  MORE  → </a>
  </footer>
</article>


            
            
            
        </div>
    </div>
</aside>


<footer class="site-footer outer">

	<div class="site-footer-content inner">
		<section class="copyright">
			<a href="/" title="Cizixs Write Here">Cizixs Write Here</a>
			&copy; 2019
		</section>
		<nav class="site-footer-nav">
			
            <a href="https://hexo.io" title="Hexo" target="_blank" rel="noopener">Hexo</a>
            <a href="https://github.com/xzhih/hexo-theme-casper" title="Casper" target="_blank" rel="noopener">Casper</a>
        </nav>
    </div>
</footer>






<div class="floating-header" >
	<div class="floating-header-logo">
        <a href="/" title="Cizixs Write Here">
			
                <img src="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg" alt="Cizixs Write Here icon" />
			
            <span>Cizixs Write Here</span>
        </a>
    </div>
    <span class="floating-header-divider">&mdash;</span>
    <div class="floating-header-title">Go 语言 JSON 简介</div>
    <progress class="progress" value="0">
        <div class="progress-container">
            <span class="progress-bar"></span>
        </div>
    </progress>
</div>
<script>
   $(document).ready(function () {
    var progressBar = document.querySelector('progress');
    var header = document.querySelector('.floating-header');
    var title = document.querySelector('.post-full-title');
    var lastScrollY = window.scrollY;
    var lastWindowHeight = window.innerHeight;
    var lastDocumentHeight = $(document).height();
    var ticking = false;

    function onScroll() {
        lastScrollY = window.scrollY;
        requestTick();
    }
    function requestTick() {
        if (!ticking) {
            requestAnimationFrame(update);
        }
        ticking = true;
    }
    function update() {
        var rect = title.getBoundingClientRect();
        var trigger = rect.top + window.scrollY;
        var triggerOffset = title.offsetHeight + 35;
        var progressMax = lastDocumentHeight - lastWindowHeight;
            // show/hide floating header
            if (lastScrollY >= trigger + triggerOffset) {
                header.classList.add('floating-active');
            } else {
                header.classList.remove('floating-active');
            }
            progressBar.setAttribute('max', progressMax);
            progressBar.setAttribute('value', lastScrollY);
            ticking = false;
        }

        window.addEventListener('scroll', onScroll, {passive: true});
        update();

        // TOC
        var width = $('.toc-main').width();
        $('.toc-control').click(function () {
            if ($('.t-g-control').css('width')=="50px") {
                if ($('.t-g-control').css('right')=="0px") {
                    $('.t-g-control').animate({right: width}, "slow");
                    $('.toc-main').animate({right: 0}, "slow");
                    toc_icon()
                } else {
                    $('.t-g-control').animate({right: 0}, "slow");
                    $('.toc-main').animate({right: -width}, "slow");
                    toc_icon()
                }
            } else {
                if ($('.toc-main').css('right')=="0px") {
                    $('.toc-main').slideToggle("fast", toc_icon());
                } else {
                    $('.toc-main').css('right', '0px');
                    toc_icon()
                }
            }
        })

        function toc_icon() {
            if ($('.toc-icon').css('display')=="none") {
                $('.toc-close').hide();
                $('.toc-icon').show();
            } else {
                $('.toc-icon').hide();
                $('.toc-close').show();
            }
        }

        $('.gotop').click(function(){
            $('html,body').animate({scrollTop:$('.post-full-header').offset().top}, 800);
        });
        $('.gobottom').click(function () {
            $('html,body').animate({scrollTop:$('.pagination').offset().top}, 800);
        });

        // highlight
        // https://highlightjs.org
        $('pre code').each(function(i, block) {
            hljs.highlightBlock(block);
        });
        $('td.code').each(function(i, block) {
            hljs.highlightBlock(block);
        });

        console.log("this theme is from https://github.com/xzhih/hexo-theme-casper")
    });
</script>



<link rel="stylesheet" href="https://cdn.staticfile.org/lightgallery/1.3.9/css/lightgallery.min.css">



<script src="https://cdn.staticfile.org/lightgallery/1.3.9/js/lightgallery.min.js"></script>


<script>
	$(function () {
		var postImg = $('#lightgallery').find('img');
		postImg.addClass('post-img');
		postImg.each(function () {
			var imgSrc = $(this).attr('src');
			$(this).attr('data-src', imgSrc);
		});
		$('#lightgallery').lightGallery({selector: '.post-img'});
	});
</script>



<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/

var disqus_config = function () {
this.page.url = 'http://cizixs.com/2016/12/19/golang-json-guide/';  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = 'http://cizixs.com/2016/12/19/golang-json-guide/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};

(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://cizixs.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
                            


    </div>
</body>
</html>
